package yxy.cherry.battle.module.affix;

import yxy.apple.util.RandomUtility;
import yxy.cherry.battle.Battle;
import yxy.cherry.battle.BattleFomula;
import yxy.cherry.battle.Fighter;
import yxy.cherry.battle.module.PropertyData;
import yxy.cherry.battle.module.TriggerPoint;
import yxy.cherry.battle.module.affix.AffixContext.AffixAction;
import yxy.cherry.battle.module.affix.condition.AffixCondition;
import yxy.cherry.battle.module.record.Record;
import yxy.cherry.battle.module.record.Recorder;
import yxy.cherry.data.bean.skill;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.Set;

/** 词缀 */
public abstract class Affix extends Recorder {

	protected static int CAMPS_SELF = 0;
	protected static int CAMPS_OPPONENT = 1;
	protected static int CAMPS_BOTH = 2;

	protected static long EFFECT_CRIT = 1L;//暴击
	protected static long EFFECT_DODGE = 2L;//闪避
	protected static long EFFECT_AVOID_KILL = 3L;//免死
	protected static long EFFECT_SHIELD = 4L;//护盾

	String name;

	skill skilldata;

	TriggerPoint triggerPoint;// 词缀生效的检查点

	Set<AffixCondition> conditionSet = new HashSet<>();

	PropertyData propertyData;// 词缀属性影响
	PropertyData targetPropertyData;// 对手词缀属性影响

	Fighter actor;

	int[] params;

	public Affix(Fighter actor, skill skilldata, int[] params) {
		this.actor = actor;
		this.skilldata = skilldata;
		this.params = params;

		this.name = skilldata.getName();

		triggerPoint = TriggerPoint.valueOf(skilldata.getTrigger());
	}

	public TriggerPoint getTriggerPoint() {
		return triggerPoint;
	}

	public int[] getParams() {
		return params;
	}

	public int getParam(int index) {
		if (params == null || params.length <= index) {
			return 0;
		}
		return params[index];
	}

	public void setPropertyData(PropertyData propertyData) {
		this.propertyData = propertyData;
	}

	public PropertyData getPropertyData() {
		return propertyData;
	}

	public PropertyData getTargetPropertyData() {
		return targetPropertyData;
	}

	public void setTargetPropertyData(PropertyData targetPropertyData) {
		this.targetPropertyData = targetPropertyData;
	}

	public void addAffixCondition(AffixCondition affixCondition) {
		conditionSet.add(affixCondition);
	}

	public Collection<AffixCondition> getConditionSet() {
		return conditionSet;
	}

	public AffixContext getAffixContext() {
		return actor.getAffixContext();
	}

	public Fighter getActor() {
		return actor;
	}

	public skill getSkilldata() {
		return skilldata;
	}

	abstract public boolean active();

	protected AffixAction getAffixAction() {
		if (getAffixContext().is附加行动中()) {
			return getAffixContext().get附加行动();
		}
		return getAffixContext().get攻击行动();
	}

	/**
	 * 通用的增伤计算
	 * @param damageFlowList
	 * @param baseDamageList
	 * @param addPer
	 * @return
	 */
	protected ArrayList<Long> genFinalDamage(ArrayList<Long> damageFlowList, ArrayList<Long> baseDamageList, int addPer){
		ArrayList<Long> finalDamageList = new ArrayList<>();
		for (int i = 0;i< baseDamageList.size(); i++) {
			long damage = damageFlowList.get(i) + baseDamageList.get(i) * addPer / VALUE_比率分母;
			finalDamageList.add(damage);
		}
		return finalDamageList;
	}

	/**
	 * 通用的增伤计算
	 * @param damageFlowList
	 * @param baseDamageList
	 * @param addPer
	 * @return
	 */
	protected ArrayList<Long> genAddDamage(ArrayList<Long> damageFlowList, ArrayList<Long> baseDamageList, int addPer){
		ArrayList<Long> finalDamageList = new ArrayList<>();
		for (int i = 0;i< baseDamageList.size(); i++) {
			long damage = baseDamageList.get(i) * addPer / VALUE_比率分母;
			finalDamageList.add(damage);
		}
		return finalDamageList;
	}

	/**
	 * 纯粹靠数值的增伤
	 * @param addDamage
	 * @return
	 */
	protected ArrayList<Long> genAddDamage(long addDamage){
		ArrayList<Long> finalDamageList = new ArrayList<>();
		finalDamageList.add(addDamage);
		return finalDamageList;
	}


	/**
	 * 通用的减伤计算
	 * @param damageFlowList
	 * @param baseDamageList
	 * @param reducePer
	 * @return
	 */
	protected ArrayList<Long> genReduceDamage(ArrayList<Long> damageFlowList, ArrayList<Long> baseDamageList, int reducePer){
		ArrayList<Long> finalDamageList = new ArrayList<>();
		for (int i = 0;i< baseDamageList.size(); i++) {
			long reduceDamage = baseDamageList.get(i) * reducePer / VALUE_比率分母;
			long damage = Math.max(damageFlowList.get(i) - reduceDamage,0);

			finalDamageList.add(damage);
		}
		//遇到附带伤害的时候需要附带上去
		if(damageFlowList.size()>baseDamageList.size()){
			for(int i = baseDamageList.size();i<damageFlowList.size();i++){
				finalDamageList.add(damageFlowList.get(i));
			}
		}
		return finalDamageList;
	}

	// 计算公式//////////////////////////////////////////////////////////////////////////

	final static public int VALUE_比率分母 = 10000;

	protected boolean is命中(Fighter actor, Fighter target) {
		Double ppm = Double.valueOf(RandomUtility.ppm());
		Double 命中概率 = BattleFomula.命中概率(target.get闪避(), actor.get命中());
		Battle.battleLogger(7,"命中："+actor.get命中()+"防守方闪避："+target.get闪避()+"随机数："+ppm+"真实命中率："+命中概率);
		return  ppm < 命中概率;
	}

	protected boolean is暴击(Fighter actor, Fighter target) {
		Double ppm = Double.valueOf(RandomUtility.ppm());
		Double 暴击概率 = BattleFomula.暴击概率(target.get抗暴(), actor.get暴击());
		Battle.battleLogger(7,"暴击："+actor.get暴击()+"暴伤："+actor.get暴伤()+"防守方抗暴："+target.get抗暴()+"韧性："+target.get韧性()+"随机数："+ppm+"真实暴击率："+暴击概率);
		return ppm < 暴击概率;
	}

	protected boolean is控制(Fighter actor, Fighter target, int probability) {
		Double ppm = Double.valueOf(RandomUtility.ppm());
		Double 控制概率 = BattleFomula.控制概率(target.get抗控(), actor.get控制(), probability);
		Battle.battleLogger(7,"控制："+actor.get控制()+"抗控："+target.get抗控()+"技能概率："+probability+"随机数："+ppm+"真实控制概率："+控制概率);
		return ppm < 控制概率;
	}

	protected double get暴击伤害比例(Fighter actor, Fighter target) {
		return BattleFomula.爆伤增伤(target.get韧性(), actor.get暴伤());
	}

	protected double get伤害(Fighter actor, Fighter target, boolean is无视防御, long attackSpecial) {
//		double 攻击 = is暴击 ? BattleFomula.暴击伤害(actor.get攻击()) * get暴击伤害比例(actor, target) : actor.get攻击();
//		double 物防 = Double.valueOf(is无视防御 ? 0 : target.get物防());
//		double value = BattleFomula.物理防御减伤(攻击, 物防);
		double actorAttack = actor.get攻击();
		if(attackSpecial > 0){actorAttack = attackSpecial;}
		double targetDefense = Double.valueOf(is无视防御 ? 0 : target.get防御());
		double value = BattleFomula.物理原始伤害(actorAttack, targetDefense);
		return value;
	}

	protected double get法术伤害(Fighter actor, Fighter target, boolean is无视防御, long attackSpecial) {
//		double 攻击 = is暴击 ? BattleFomula.暴击伤害(actor.get攻击()) * get暴击伤害比例(actor, target) : actor.get攻击();
//		double 法防 = Double.valueOf(is无视防御 ? 0 : target.get法防());
//		double value = BattleFomula.法术防御减伤(攻击, 法防);
		double actorAttack = actor.get攻击();
		if(attackSpecial > 0){actorAttack = attackSpecial;}
		double targetDefense = Double.valueOf(is无视防御 ? 0 : target.get法防());
		double value = BattleFomula.法术原始伤害(actorAttack, targetDefense);
		return value;
	}

	protected double get增加伤害比例(Fighter actor, Fighter target) {
		//临时计算兵符带来的增减伤，按照阵营进行计算
		String addKey = target.get阵营()+"_"+"0";
		double commanderSealAddPer = 0;
		if(actor.getTeam().getCommanderSeal().get(addKey) != null) {
			commanderSealAddPer = actor.getTeam().getCommanderSeal().get(addKey);
		}
		String reduceKey = actor.get阵营()+"_"+"1";
		double commanderSealReducePer = 0;
		if(target.getTeam().getCommanderSeal().get(reduceKey) != null) {
			commanderSealReducePer = target.getTeam().getCommanderSeal().get(reduceKey);
		}

		Battle.battleLogger(6,"兵符加成："+"出手者："+actor.getName()+"对"+target.get阵营()+"增伤："+commanderSealAddPer+":受击者："+target.getName()+"对"+actor.get阵营()+"减伤："+commanderSealReducePer);

		return BattleFomula.增伤(target.get减伤()+commanderSealReducePer, actor.get增伤()+commanderSealAddPer, target.get法减(), actor.get法增());
	}

	protected double get总伤害比例(Fighter actor, Fighter target, double 伤害比例, double 克制伤害比例) {
		double value = 伤害比例 + 克制伤害比例;
		return VALUE_比率分母 + value;
	}

	protected double get法术总伤害比例(Fighter actor, Fighter target, double 法术伤害比例, double 克制伤害比例) {
		double value = 法术伤害比例 + 克制伤害比例;
		return VALUE_比率分母 + value;
	}

	protected double get治疗增幅(Fighter actor, Fighter target) {
		return BattleFomula.治疗增量(target.get受疗(), actor.get治疗());
	}

	@Override
	public void transmitRecord(Record record) {
	}

	@Override
	public String toString() {
		return name;
	}
}
